package creation

import (
	"context"
	"fmt"
	"github.com/Masterminds/sprig/v3"
	"github.com/nuttech/bell"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	v1alpha12 "gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
	"gitverse.ru/synapse/kubelatte/pkg/observability/logs"
	"gitverse.ru/synapse/kubelatte/pkg/operator"
	"gitverse.ru/synapse/kubelatte/pkg/operator/controllers/clientset"
	"gitverse.ru/synapse/kubelatte/pkg/operator/controllers/clientset/mocks"
	"gitverse.ru/synapse/kubelatte/pkg/storage"
	"gitverse.ru/synapse/kubelatte/pkg/util/templates"
	"go.uber.org/zap"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"strings"
	"testing"
	"text/template"
	"time"
)

func TestRenderController(t *testing.T) {
	logs.Logger = zap.NewNop()

	templateClient := mocks.NewTemplateInterface(t)
	templateClient.On("List", mock.Anything, mock.Anything).Return(&v1alpha12.TemplateList{
		Items: []v1alpha12.Template{
			{
				ObjectMeta: v1.ObjectMeta{
					Name:      "template",
					Namespace: "test",
				},
				Spec: v1alpha12.TemplateSpec{
					Kind:       "Pod",
					ApiVersion: "v1",
					Data:       "metadata:\n name: pod\nspec:\n abc: test",
				},
			},
		},
	}, nil).Maybe()
	triggerClient := mocks.NewTriggerInterface(t)
	triggerClient.On("List", mock.Anything, mock.Anything).Return(&v1alpha12.TriggerList{
		Items: []v1alpha12.Trigger{
			{
				ObjectMeta: v1.ObjectMeta{
					Name:      "trigger",
					Namespace: "test",
				},
				Spec: v1alpha12.TriggerSpec{
					CreationConfigs: []v1alpha12.CreationConfig{
						{
							Name: "creation",
							LabelSelector: v1.LabelSelector{
								MatchExpressions: []v1.LabelSelectorRequirement{
									{
										Key:      "test",
										Operator: "In",
										Values:   []string{"test"},
									},
								},
							},
							AnnotationNamespace: "test",
							AnnotationTrigger:   "test",
							TemplateRefs:        []string{"test/template"},
						},
					},
				},
			},
		},
	}, nil).Maybe()

	ti := v1alpha12.TriggerInstance{
		Status: v1alpha12.TriggerInstanceStatus{
			ResourceStatus: []v1alpha12.ResourceStatus{
				{
					Name:       "pod",
					Kind:       "Pod",
					ApiVersion: "v1",
					Message:    "REMOVED",
					Phase:      "",
					Status:     "REMOVED",
				},
			},
		},
	}

	scopeClient := mocks.NewScopeInterface(t)
	triggerInstanceClient := mocks.NewTriggerInstanceInterface(t)
	triggerInstanceClient.On("Get", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&ti, nil).Maybe()
	triggerInstanceClient.On("UpdateStatus", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil).Maybe()

	clt := clientset.V1Alpha1Client{
		TriggerClient:         triggerClient,
		TemplateClient:        templateClient,
		ScopeClient:           scopeClient,
		TriggerInstanceClient: triggerInstanceClient,
	}

	operator.Cl = &clt

	r := RenderController{}
	InitTestStorage()

	t.Run("Check CheckTriggerTemplatePair", func(t *testing.T) {
		r.CheckTriggerTemplatePair(context.Background())
	})
	t.Run("Check getRenders", func(t *testing.T) {
		ti2 := v1alpha12.TriggerInstance{
			ObjectMeta: v1.ObjectMeta{
				Name:      "test",
				Namespace: "test",
				Annotations: map[string]string{
					"test/test": "true",
				},
			},
			Status: v1alpha12.TriggerInstanceStatus{},
		}
		renderItems := r.GetRenders(context.Background(), &ti2)
		assert.Equal(t, 1, len(renderItems))
	})
}

func InitTestStorage() {
	var storageController = &storage.StorageController{}
	storageController.Start(false, false)
	storageController.UpdateScope(bell.Message{
		Event:     "",
		Timestamp: time.Now(),
		Value: v1alpha12.Scope{
			ObjectMeta: v1.ObjectMeta{
				Name: "TestScope",
			},
			Spec: v1alpha12.ScopeSpec{
				Type: "mutation",
				Items: []v1alpha12.Item{
					{
						Name: "TestScopeItem",
					},
				},
			},
		},
	})
	storageController.UpdateTrigger(bell.Message{
		Event:     "",
		Timestamp: time.Now(),
		Value: v1alpha12.Trigger{
			ObjectMeta: v1.ObjectMeta{
				Name:      "trigger",
				Namespace: "test",
			},
			Spec: v1alpha12.TriggerSpec{
				CreationConfigs: []v1alpha12.CreationConfig{
					{
						Name: "creation",
						LabelSelector: v1.LabelSelector{
							MatchExpressions: []v1.LabelSelectorRequirement{
								{
									Key:      "test",
									Operator: "In",
									Values:   []string{"test"},
								},
							},
						},
						AnnotationNamespace: "test",
						AnnotationTrigger:   "test",
						TemplateRefs:        []string{"test/template"},
					},
				},
			},
		},
	})
	storageController.UpdateTemplate(bell.Message{
		Event:     "",
		Timestamp: time.Now(),
		Value: v1alpha12.Template{
			ObjectMeta: v1.ObjectMeta{
				Name:      "template",
				Namespace: "test",
			},
			Spec: v1alpha12.TemplateSpec{
				Kind:       "Pod",
				ApiVersion: "v1",
				Data:       "metadata:\n name: pod\nspec:\n abc: test",
			},
		},
	})
	storage.Storage = storageController
}

func TestTemplateEngine(t *testing.T) {
	var Data = "{{% .spec.dataObj.spec.host %}}"
	var tiObject = map[string]interface{}{
		"spec": map[string]interface{}{
			"dataObj": map[string]interface{}{
				"spec": map[string]interface{}{
					"host": "aaaaaaaaaa",
				},
			},
		},
	}
	templateEngine := template.New("common").
		Delims("{{%", "%}}").
		Funcs(template.FuncMap{
			"fromYaml": templates.FromYAML,
		}).
		Funcs(sprig.TxtFuncMap())
	temp, err := templateEngine.New("test").Parse(Data)
	if err != nil {
		_ = fmt.Errorf(fmt.Sprintf("TestTemplateEngine: ReloadTemplates failed %s", err))
	}
	var tempBuffer strings.Builder
	err = temp.Execute(&tempBuffer, tiObject)
	if err != nil {
		_ = fmt.Errorf(fmt.Sprintf("RenderController: getRenders failed %s", err))
	}
	fmt.Println(tempBuffer.String())
}
